home *** CD-ROM | disk | FTP | other *** search
- Subject: v16i082: Mail delivery program, Part02/03
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Chip Salzenberg <ateng!chip@uunet.uu.net>
- Posting-number: Volume 16, Issue 82
- Archive-name: deliver/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: context.c copymsg.c debug.c dest.c dfile.c lock.c
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'context.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'context.c'\"
- else
- echo shar: Extracting \"'context.c'\" \(2596 characters\)
- sed "s/^X//" >'context.c' <<'END_OF_FILE'
- X/* $Header: context.c,v 1.3 88/09/14 19:41:40 network Exp $
- X *
- X * User context manager.
- X * This module exists for efficiency reasons; I could just call getpwnam()
- X * every time I need context info.
- X *
- X * $Log: context.c,v $
- X * Revision 1.3 88/09/14 19:41:40 network
- X * Portability to System V and BSD.
- X * General fixup.
- X *
- X * Revision 1.2 88/08/30 16:12:28 network
- X * Use savestr() instead of strdup().
- X *
- X * Revision 1.1 88/06/06 09:38:05 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <pwd.h>
- X#include <grp.h>
- X
- Xextern struct passwd *getpwnam();
- Xextern struct passwd *getpwuid();
- Xextern struct group *getgrnam();
- Xextern struct group *getgrgid();
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic CONTEXT *new_context();
- X
- X/*
- X * Local data.
- X */
- X
- Xstatic CONTEXT *ctlist; /* Chain of CONTEXT structures. */
- X
- X/*----------------------------------------------------------------------
- X * Look up a context by user name.
- X */
- X
- XCONTEXT *
- Xname_context(name)
- Xchar *name;
- X{
- X struct passwd *pw;
- X CONTEXT *ct;
- X
- X for (ct = ctlist; ct; ct = ct->next)
- X {
- X if (strcmp(ct->name, name) == 0)
- X return ct;
- X }
- X
- X if ((pw = getpwnam(name)) == NULL)
- X return NULL;
- X
- X return new_context(pw);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Look up a context by user ID.
- X */
- X
- XCONTEXT *
- Xuid_context(uid)
- Xint uid;
- X{
- X struct passwd *pw;
- X CONTEXT *ct;
- X
- X for (ct = ctlist; ct; ct = ct->next)
- X {
- X if (ct->uid == uid)
- X return ct;
- X }
- X
- X if ((pw = getpwuid(uid)) == NULL)
- X return NULL;
- X
- X return new_context(pw);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Local function -- create a new context structure and return
- X * its address.
- X */
- X
- Xstatic CONTEXT *
- Xnew_context(pw)
- Xstruct passwd *pw;
- X{
- X CONTEXT *ct;
- X
- X ct = (CONTEXT *) zalloc(sizeof(CONTEXT));
- X ct->uid = pw->pw_uid;
- X ct->gid = pw->pw_gid;
- X ct->name = copystr(pw->pw_name);
- X ct->home = copystr(pw->pw_dir);
- X
- X ct->next = ctlist;
- X ctlist = ct;
- X
- X return ct;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Report whether is is possible or not to enter the given context.
- X */
- X
- Xint
- Xok_context(ct)
- XCONTEXT *ct;
- X{
- X if (! ct)
- X return FALSE;
- X
- X if (eff_uid == 0
- X || ((real_uid == ct->uid) && (real_gid == ct->gid)))
- X return TRUE;
- X else
- X return FALSE;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Look up a group ID by name.
- X */
- X
- X#ifdef MAILBOX_GROUP
- X
- Xint
- Xgroup_id(name)
- Xchar *name;
- X{
- X struct group *grp;
- X
- X if ((grp = getgrnam(name)) == NULL)
- X return -1;
- X
- X return grp->gr_gid;
- X}
- X
- X#endif /* MAILBOX_GROUP */
- END_OF_FILE
- if test 2596 -ne `wc -c <'context.c'`; then
- echo shar: \"'context.c'\" unpacked with wrong size!
- fi
- # end of 'context.c'
- fi
- if test -f 'copymsg.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'copymsg.c'\"
- else
- echo shar: Extracting \"'copymsg.c'\" \(5998 characters\)
- sed "s/^X//" >'copymsg.c' <<'END_OF_FILE'
- X/* $Header: copymsg.c,v 1.1 88/06/06 09:38:13 chip Exp $
- X *
- X * Take the message from standard input and write it to two temp files,
- X * one for the header (including the empty line) and one for the body.
- X *
- X * $Log: copymsg.c,v $
- X * Revision 1.1 88/06/06 09:38:13 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*
- X * Macros.
- X */
- X
- X/* Does a string start with "From "? */
- X
- X#define ISFROM(p) ((p)[0] == 'F' && (p)[1] == 'r' && (p)[2] == 'o' \
- X && (p)[3] == 'm' && (p)[4] == ' ')
- X
- X/*
- X * Local functions.
- X */
- X
- Xstatic char *tempfile();
- Xstatic int tcreate();
- X
- X/*----------------------------------------------------------------------
- X * Copy the message on the standard input to two temp files:
- X * one for the header and one for the body.
- X */
- X
- Xint
- Xcopy_message()
- X{
- X char buf[BUFSIZ];
- X FILE *dfp[T_MAX];
- X char *p, *fsender, *fremote, *osender, *oremote;
- X long now;
- X int t, b, empty_line;
- X int ret = 0;
- X
- X /*
- X * Create temporary files to hold the header and message body.
- X */
- X
- X for (t = 0; t < T_MAX; ++t)
- X {
- X int fd;
- X
- X tfile[t] = tempfile();
- X if ((tfd[t] = tcreate(tfile[t])) == -1)
- X return -1;
- X
- X if ((fd = dup(tfd[t])) == -1)
- X {
- X syserr("dup %s fd", ttype[t]);
- X return -1;
- X }
- X (void) lseek(fd, 0L, 0);
- X if ((dfp[t] = fdopen(fd, "r+")) == NULL)
- X {
- X error("can't fdopen %s fd", ttype[t]);
- X return -1;
- X }
- X }
- X
- X /* Debugging message for later examination of temp files. */
- X
- X if (verbose)
- X {
- X message("header=%s, body=%s\n",
- X tfile[T_HEADER], tfile[T_BODY]);
- X }
- X
- X /*
- X * If there is a From_ line, find the sender name therein.
- X */
- X
- X fsender = fremote = NULL;
- X
- X b = (fgets(buf, GETSIZE(buf), stdin) ? TRUE : FALSE);
- X
- X if (b && ISFROM(buf) && (p = strchr(buf, '\n')) != NULL)
- X {
- X b = FALSE; /* Don't output two From_ lines */
- X *p = 0;
- X
- X /* Find sender */
- X
- X for (fsender = buf + 5; isspace(*fsender); ++fsender)
- X ; /* until sender */
- X for (p = fsender; *p && !isspace(*p); ++p)
- X ; /* until end of sender */
- X if (*p)
- X *p++ = '\0';
- X
- X /* Find 'remote from' phrase (if any) */
- X
- X for (fremote = p;
- X (fremote = strchr(fremote, 'r')) != NULL;
- X ++fremote)
- X {
- X if (strncmp(fremote, "remote from", 11) == 0)
- X {
- X fremote += 11;
- X while (isspace(*fremote))
- X ++fremote;
- X break;
- X }
- X }
- X }
- X
- X /*
- X * Write a From_ line to the header file.
- X * If the user specified a sender name, use it;
- X * else if we found a From_ line, use the sender found therein;
- X * else use the user name of our real UID.
- X */
- X
- X if (sender && *sender)
- X {
- X osender = sender;
- X oremote = NULL;
- X }
- X else if (fsender)
- X {
- X osender = fsender;
- X oremote = fremote;
- X }
- X else
- X {
- X osender = real_ct->name;
- X oremote = NULL;
- X }
- X
- X (void) fputs("From ", dfp[T_HEADER]);
- X if (oremote)
- X {
- X (void) fputs(oremote, dfp[T_HEADER]);
- X (void) fputc('!', dfp[T_HEADER]);
- X }
- X (void) fputs(osender, dfp[T_HEADER]);
- X (void) fputc(' ', dfp[T_HEADER]);
- X (void) time(&now);
- X (void) fputs(ctime(&now), dfp[T_HEADER]);
- X
- X /*
- X * Copy the rest of the header (if any).
- X */
- X
- X for (; !feof(stdin); b = FALSE)
- X {
- X if (!b)
- X {
- X if (fgets(buf, GETSIZE(buf), stdin))
- X b = TRUE;
- X else
- X break;
- X }
- X
- X /* Empty line means "end of header" */
- X
- X if (buf[0] == '\n')
- X {
- X b = FALSE; /* Don't put this line in the body. */
- X break;
- X }
- X
- X /*
- X * A line too long to fit in buf[] can't be a header line.
- X * At least, that's my opinion... :-)
- X */
- X
- X if (!strchr(buf, '\n'))
- X break;
- X
- X /*
- X * If line begins with whitespace, it's a continuation.
- X * Else if line begins with From_ or '>', prepend '>'.
- X * Else if line doesn't look like a header, this must
- X * be the beginning of the body.
- X */
- X
- X if (isspace(buf[0]))
- X ; /* continuation */
- X else if (ISFROM(buf) || (buf[0] == '>'))
- X (void) fputc('>', dfp[T_HEADER]);
- X else
- X {
- X /* look for the colon on a header label */
- X
- X p = buf;
- X while (isalpha(*p) || *p == '-')
- X ++p;
- X if ((p == buf) || (*p != ':'))
- X break; /* Not a header line! */
- X }
- X
- X /* Write the line to the header file. */
- X
- X (void) fputs(buf, dfp[T_HEADER]);
- X }
- X
- X /*
- X * End the header file with a blank line.
- X * This enables us to simply concatenate it with the body file
- X * to produce a valid message.
- X */
- X
- X (void) fputc('\n', dfp[T_HEADER]);
- X
- X /*
- X * Copy the body (if any).
- X */
- X
- X empty_line = FALSE;
- X for (; !feof(stdin); b = FALSE)
- X {
- X if (!b)
- X {
- X if (fgets(buf, GETSIZE(buf), stdin))
- X b = TRUE;
- X else
- X break;
- X }
- X
- X if (ISFROM(buf))
- X (void) fputc('>', dfp[T_BODY]);
- X (void) fputs(buf, dfp[T_BODY]);
- X
- X empty_line = (buf[0] == '\n');
- X
- X /*
- X * Output the rest of a very long line.
- X * We do this here, instead of going around the loop,
- X * in order to avoid misinterpreting From_ strings
- X * that may be found in long lines.
- X */
- X
- X while (!strchr(buf, '\n')
- X && !feof(stdin)
- X && fgets(buf, GETSIZE(buf), stdin))
- X (void) fputs(buf, dfp[T_BODY]);
- X }
- X
- X /* Ensure that the body ends with a blank line. */
- X
- X if (! empty_line)
- X (void) fputc('\n', dfp[T_BODY]);
- X
- X /*
- X * If we encountered any trouble writing to the temp files,
- X * let's not keep it secret.
- X */
- X
- X for (t = 0; t < T_MAX; ++t)
- X {
- X if (ferror(dfp[t]))
- X {
- X error("error writing to %s file %s\n",
- X ttype[t], tfile[t]);
- X ret = -1;
- X }
- X
- X (void) fclose(dfp[t]);
- X }
- X
- X /* Return error/success. */
- X
- X return ret;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return a pointer to a temporary filename, or NULL if error.
- X */
- X
- Xstatic char *
- Xtempfile()
- X{
- X static char template[] = "/tmp/dl.XXXXXX";
- X char *f;
- X
- X f = zalloc(32);
- X (void) strcpy(f, template);
- X if (mktemp(f) == NULL)
- X {
- X error("can't create temporary file");
- X return NULL;
- X }
- X return f;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Create a file, or complain if it doesn't work.
- X */
- X
- Xstatic int
- Xtcreate(name)
- Xchar *name;
- X{
- X int fd;
- X
- X if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)
- X {
- X syserr("can't create %s", name);
- X return -1;
- X }
- X
- X return fd;
- X}
- X
- END_OF_FILE
- if test 5998 -ne `wc -c <'copymsg.c'`; then
- echo shar: \"'copymsg.c'\" unpacked with wrong size!
- fi
- # end of 'copymsg.c'
- fi
- if test -f 'debug.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'debug.c'\"
- else
- echo shar: Extracting \"'debug.c'\" \(1003 characters\)
- sed "s/^X//" >'debug.c' <<'END_OF_FILE'
- X/* $Header: debug.c,v 1.1 88/06/06 09:38:23 chip Exp $
- X *
- X * Debugging output.
- X *
- X * $Log: debug.c,v $
- X * Revision 1.1 88/06/06 09:38:23 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*----------------------------------------------------------------------
- X * Print out a complete dump of all destinations
- X */
- X
- Xdumpdests(when)
- Xchar *when;
- X{
- X DEST *d;
- X
- X message("Destinations %s:\n", when);
- X for (d = first_dest(); d; d = next_dest(d))
- X {
- X message("\t%s", d->name);
- X if (d->class == CL_MBOX)
- X message(":%s", d->mailbox);
- X
- X message(" (");
- X switch (d->class)
- X {
- X case CL_USER:
- X message("User");
- X break;
- X case CL_MBOX:
- X message("Mailbox");
- X break;
- X case CL_UUCP:
- X message("UUCP");
- X break;
- X }
- X message(", ");
- X switch (d->state)
- X {
- X case ST_WORKING:
- X message("Working");
- X break;
- X case ST_HOLD:
- X message("Hold");
- X break;
- X case ST_DONE:
- X message("Done");
- X break;
- X case ST_ERROR:
- X message("Error: %s", d->error);
- X break;
- X }
- X message(")\n");
- X }
- X}
- END_OF_FILE
- if test 1003 -ne `wc -c <'debug.c'`; then
- echo shar: \"'debug.c'\" unpacked with wrong size!
- fi
- # end of 'debug.c'
- fi
- if test -f 'dest.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dest.c'\"
- else
- echo shar: Extracting \"'dest.c'\" \(2079 characters\)
- sed "s/^X//" >'dest.c' <<'END_OF_FILE'
- X/* $Header: dest.c,v 1.2 88/08/30 16:12:40 network Exp $
- X *
- X * Operations on the list of mail destinations.
- X *
- X * $Log: dest.c,v $
- X * Revision 1.2 88/08/30 16:12:40 network
- X * Use savestr() instead of strdup().
- X *
- X * Revision 1.1 88/06/06 09:38:29 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*
- X * Local data.
- X */
- X
- Xstatic DEST deadhead = { &deadhead, &deadhead };
- X#define HEADPTR (&deadhead)
- X
- X/*----------------------------------------------------------------------
- X * Add a new destination to the list (unless it already exists).
- X * Return pointer to DEST.
- X */
- X
- XDEST *
- Xdest(name, mailbox)
- Xchar *name;
- Xchar *mailbox;
- X{
- X DEST *d;
- X DCLASS class;
- X
- X if (strchr(name, '!'))
- X class = CL_UUCP;
- X else if (mailbox)
- X class = CL_MBOX;
- X else
- X class = CL_USER;
- X
- X for (d = HEADPTR->next; d != HEADPTR; d = d->next)
- X {
- X if (d->class != class)
- X continue;
- X
- X if (strcmp(d->name, name) != 0)
- X continue;
- X
- X /*
- X * If this destination has a named mailbox, then
- X * test it for equality as well.
- X */
- X
- X if (class == CL_MBOX
- X && strcmp(d->mailbox, mailbox) != 0)
- X continue;
- X
- X /*
- X * Like, gnarly, dude! It's already in the chain!
- X */
- X
- X return d;
- X }
- X
- X /*
- X * The given dest isn't in the list, so we have to add it.
- X */
- X
- X d = (DEST *) zalloc(sizeof(DEST));
- X d->class = class;
- X d->state = ST_WORKING;
- X d->name = copystr(name);
- X if (class == CL_MBOX)
- X d->mailbox = copystr(mailbox);
- X
- X if (class != CL_UUCP
- X && name_context(name) == NULL)
- X {
- X d->state = ST_ERROR;
- X d->error = "No such user";
- X }
- X
- X d->prev = HEADPTR->prev;
- X d->next = HEADPTR;
- X d->prev->next = d;
- X d->next->prev = d;
- X
- X return d;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return pointer to first DEST in the list.
- X */
- X
- XDEST *
- Xfirst_dest()
- X{
- X if (HEADPTR->next != HEADPTR)
- X return HEADPTR->next;
- X
- X return NULL;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return pointer to next DEST in the list, or NULL.
- X */
- X
- XDEST *
- Xnext_dest(d)
- XDEST *d;
- X{
- X if (d && (d = d->next) != HEADPTR)
- X return d;
- X
- X return NULL;
- X}
- END_OF_FILE
- if test 2079 -ne `wc -c <'dest.c'`; then
- echo shar: \"'dest.c'\" unpacked with wrong size!
- fi
- # end of 'dest.c'
- fi
- if test -f 'dfile.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'dfile.c'\"
- else
- echo shar: Extracting \"'dfile.c'\" \(6731 characters\)
- sed "s/^X//" >'dfile.c' <<'END_OF_FILE'
- X/* $Header: dfile.c,v 1.2 88/08/25 15:23:56 network Exp $
- X *
- X * Filter destination(s) through delivery file(s).
- X *
- X * $Log: dfile.c,v $
- X * Revision 1.2 88/08/25 15:23:56 network
- X * Add third parameter to do_dfile(), so that if the delivery file cannot
- X * be executed, the given destination can be recorded as an error.
- X *
- X * Revision 1.1 88/06/06 09:38:38 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X/*----------------------------------------------------------------------
- X * Filter all valid destinations through the global delivery file.
- X */
- X
- Xsys_dfile(dac, dav)
- Xint dac;
- Xchar **dav;
- X{
- X char **fav;
- X int fac, a, goodnames;
- X struct stat st;
- X
- X /*
- X * If there is no global delivery file, then take all the named
- X * addresses verbatim and return.
- X */
- X
- X if (stat(sys_deliver, &st) == -1)
- X {
- X if (verbose)
- X message("%s: no system delivery file\n",
- X progname);
- X
- X for (a = 0; a < dac; ++a)
- X (void) dest(dav[a], (char *) NULL);
- X return;
- X }
- X
- X /*
- X * Collect the arguments for the delivery file.
- X */
- X
- X fav = (char **) zalloc((dac + 3) * sizeof(char **));
- X fav[0] = shell;
- X fav[1] = sys_deliver;
- X fac = 2;
- X
- X goodnames = 0;
- X for (a = 0; a < dac; ++a)
- X {
- X char *p;
- X
- X for (p = dav[a]; *p; ++p)
- X {
- X if (!isalpha(*p)
- X && !isdigit(*p)
- X && !strchr("#%-+._", *p))
- X break;
- X }
- X
- X if (*p)
- X {
- X /* Invalid name -- note it and go on. */
- X
- X (void) dest(dav[a], (char *) NULL);
- X }
- X else
- X {
- X /* Valid name -- let the delivery file handle it. */
- X
- X fav[fac++] = dav[a];
- X ++goodnames;
- X }
- X }
- X
- X fav[fac] = NULL;
- X
- X /*
- X * If there were any good names found, let loose the delivery
- X * file. Note the meaning of "good" is "well-formed", not "valid".
- X * Thus the system delivery file has control over the handling of
- X * all local deliveries, not just those to valid users.
- X */
- X
- X if (goodnames)
- X (void) do_dfile(eff_ct, fav, (DEST *)NULL);
- X
- X free((char *) fav);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Filter all user destinations through their local delivery files.
- X */
- X
- Xuser_dfiles()
- X{
- X DEST *d;
- X int nfound;
- X
- X /*
- X * Continue to loop through all addresses until no destination
- X * that needs expanding can be found.
- X */
- X
- X do {
- X nfound = 0;
- X for (d = first_dest(); d; d = next_dest(d))
- X {
- X if (d->class == CL_USER
- X && d->state == ST_WORKING
- X && !d->dfdone)
- X {
- X one_dfile(d);
- X d->dfdone = TRUE;
- X }
- X }
- X } while (nfound > 0);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Run the delivery file (if any) for the specified destination.
- X */
- X
- Xone_dfile(d)
- XDEST *d;
- X{
- X CONTEXT *ct;
- X char *fav[4];
- X char udel_path[100];
- X struct stat st;
- X
- X if ((ct = name_context(d->name)) == NULL)
- X {
- X d->state = ST_ERROR;
- X d->error = "Missing context in user_dfile_one()";
- X return;
- X }
- X
- X /*
- X * If user's home directory is missing, forget it.
- X * If user's home directory is writable to the world,
- X * executing the delivery file would allow a security breach!
- X * Thanks to Jon Zeeff for this hint...
- X */
- X
- X if (stat(ct->home, &st) == -1
- X || (st.st_mode & S_IFMT) != S_IFDIR)
- X {
- X if (verbose)
- X message("%s: home directory %s is missing!\n",
- X ct->name, ct->home);
- X return;
- X }
- X
- X if (st.st_mode & 02)
- X {
- X if (verbose)
- X message("%s: home directory is writable to the world!\n",
- X ct->name);
- X return;
- X }
- X
- X /*
- X * If there is no delivery file to execute, just return.
- X */
- X
- X (void) sprintf(udel_path, "%s/%s", ct->home, user_deliver);
- X if (stat(udel_path, &st) == -1)
- X {
- X if (verbose)
- X message("%s has no delivery file\n", d->name);
- X return;
- X }
- X
- X /*
- X * Time to run the file!
- X * We put this dest on hold, so that it will be ignored unless
- X * the delivery file names it.
- X */
- X
- X d->state = ST_HOLD;
- X
- X fav[0] = "sh";
- X fav[1] = udel_path;
- X fav[2] = d->name;
- X fav[3] = NULL;
- X (void) do_dfile(ct, fav, d);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Process a delivery file.
- X */
- X
- Xint
- Xdo_dfile(ct, av, d)
- XCONTEXT *ct;
- Xchar **av;
- XDEST *d;
- X{
- X FILE *fp;
- X char *name, *mailbox;
- X
- X if (!ct)
- X return -1;
- X
- X if (! ok_context(ct))
- X {
- X if (d)
- X {
- X d->state = ST_ERROR;
- X d->error = "No permissions for that context";
- X }
- X else
- X message("No permissions to run as %s\n", ct);
- X
- X return -1;
- X }
- X
- X /* Make sure that the temp files are readable to the new process. */
- X
- X give_temps(ct);
- X
- X /* Here we go! */
- X
- X if (verbose)
- X message("Processing delivery file as %s\n", ct->name);
- X
- X if ((fp = ct_popenv(ct, "/bin/sh", av, "r")) == NULL)
- X {
- X error("can't execute delivery file as %s\n", ct->name);
- X leave(1);
- X }
- X
- X /*
- X * Read the standard output of the delivery file.
- X */
- X
- X while (dfile_gets(fp, &name, &mailbox) >= 0)
- X {
- X DEST *nd;
- X
- X nd = dest(name, mailbox);
- X if (nd->state == ST_HOLD)
- X nd->state = ST_WORKING;
- X
- X /*
- X * If the delivery file specified a mailbox, verify
- X * that the user whose delivery file is running has
- X * permissions for the requested context.
- X */
- X
- X if ((nd->state == ST_WORKING) && (mailbox != NULL))
- X {
- X CONTEXT *nct;
- X
- X if ((nct = name_context(name)) == NULL)
- X {
- X nd->state = ST_ERROR;
- X nd->error = "Lost context in do_dfile()";
- X }
- X else if (! ok_context(nct))
- X {
- X nd->state = ST_ERROR;
- X nd->error = "No permissions for that context";
- X }
- X }
- X }
- X
- X return ct_pclose(fp);
- X}
- X
- X/*----------------------------------------------------------------------
- X * Get and parse a single delivery file output line.
- X */
- X
- Xint
- Xdfile_gets(fp, namep, mailboxp)
- XFILE *fp;
- Xchar **namep;
- Xchar **mailboxp;
- X{
- X char *p, *q;
- X static char buf[BUFSIZ];
- X
- X if (fgets(buf, GETSIZE(buf), fp) == NULL)
- X return -1;
- X
- X if ((p = strchr(buf, '\n')) != NULL)
- X *p = 0;
- X else
- X {
- X int c;
- X
- X while ((c = fgetc(fp)) != '\n' && c != EOF)
- X ; /* keep reading */
- X
- X error("invalid line from delivery file: '%s'\n", buf);
- X return -1;
- X }
- X
- X /* Strip out all whitespace and eliminate duplicated slashes */
- X
- X p = q = buf;
- X while (*p)
- X {
- X if (! isspace(*p))
- X {
- X if ((*q++ = *p++) == '/')
- X {
- X while (*p == '/')
- X ++p;
- X }
- X }
- X }
- X *q = 0;
- X
- X /* Debugging message: display input line */
- X
- X if (verbose)
- X message("\t'%s'\n", buf);
- X
- X if ((p = strchr(buf, ':')) != NULL)
- X {
- X *p++ = 0;
- X if ((q = strchr(p, ':')) != NULL)
- X *q = 0;
- X }
- X
- X *namep = buf;
- X *mailboxp = p;
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Make the temp files readable in the given context.
- X * This is needed because the temps are readable by owner only.
- X */
- X
- Xgive_temps(ct)
- XCONTEXT *ct;
- X{
- X int t;
- X
- X if (!ct)
- X return;
- X
- X for (t = 0; t < T_MAX; ++t)
- X {
- X if (chown(tfile[t], ct->uid, ct->gid) == -1)
- X syserr("can't chown %s", tfile[t]);
- X }
- X}
- END_OF_FILE
- if test 6731 -ne `wc -c <'dfile.c'`; then
- echo shar: \"'dfile.c'\" unpacked with wrong size!
- fi
- # end of 'dfile.c'
- fi
- if test -f 'lock.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lock.c'\"
- else
- echo shar: Extracting \"'lock.c'\" \(6559 characters\)
- sed "s/^X//" >'lock.c' <<'END_OF_FILE'
- X/* $Header: lock.c,v 1.2 88/08/30 16:13:14 network Exp $
- X *
- X * Mailbox locking.
- X * Local hacks for mailbox access should be grafted here.
- X *
- X * $Log: lock.c,v $
- X * Revision 1.2 88/08/30 16:13:14 network
- X * Portability fixes from Ronald Karr <tron@uts.amdahl.com>.
- X *
- X * Revision 1.1 88/06/06 09:38:48 chip
- X * Initial revision
- X *
- X */
- X
- X#include "deliver.h"
- X
- X/*
- X * Validate the locking configuration.
- X */
- X
- X#if (defined(ML_FCNTL) + defined(ML_LOCKF) + defined(ML_LOCKING)) > 1
- X lose! "Only one of ML_FCNTL, ML_LOCKF and ML_LOCKING may be defined.";
- X#endif
- X
- X/*
- X * Support for the lockf() system call.
- X */
- X
- X#ifdef ML_LOCKF
- X#include <unistd.h>
- X#define SIMPLE_LOCK "lockf"
- X#define LOCKFD(fd, size) lockf(fd, F_LOCK, size)
- X#define UNLOCKFD(fd, size) lockf(fd, F_ULOCK, size)
- X#endif /* ML_LOCKF */
- X
- X/*
- X * Setup for the locking() system call.
- X */
- X
- X#ifdef ML_LOCKING
- X#include <sys/types.h>
- X#include <sys/locking.h>
- X#define SIMPLE_LOCK "locking"
- X#define LOCKFD(fd, size) locking(fd, LK_LOCK, size)
- X#define UNLOCKFD(fd, size) locking(fd, LK_UNLOCK, size)
- X#endif
- X
- X/*
- X * Local functions.
- X */
- X
- X#ifdef ML_DOTLOCK
- Xstatic char *dotlock_name();
- X#endif
- X#ifdef ML_DOTMLK
- Xstatic char *dotmlk_name();
- X#endif
- X
- X/*----------------------------------------------------------------------
- X * Lock a mailbox by name.
- X *
- X * This code looks quite hairy with all the ifdefs. In fact, the only
- X * somewhat strange thing here is that neither, either, or both of
- X * ML_DOTLOCK and ML_DOTMLK may be defined, and we have to allow for it.
- X */
- X
- Xint
- Xlock_name(name)
- Xchar *name;
- X{
- X#ifdef ML_DOTLOCK
- X char *dotlock;
- X#endif
- X#ifdef ML_DOTMLK
- X char *dotmlk;
- X#endif
- X
- X#ifdef ML_DOTLOCK
- X if ((dotlock = dotlock_name(name)) == NULL
- X || create_lockfile(dotlock) < 0)
- X return -1;
- X#endif /* ML_DOTLOCK */
- X
- X#ifdef ML_DOTMLK
- X if ((dotmlk = dotmlk_name(name)) == NULL
- X || create_lockfile(dotmlk) < 0)
- X {
- X#ifdef ML_DOTLOCK
- X (void) remove_lockfile(dotlock); /* don't leave me hanging */
- X#endif
- X return -1;
- X }
- X#endif /* ML_DOTMLK */
- X
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Unlock a mailbox by name.
- X */
- X
- Xint
- Xunlock_name(name)
- Xchar *name;
- X{
- X int ret = 0;
- X
- X#ifdef ML_DOTLOCK
- X char *dotlock;
- X#endif
- X#ifdef ML_DOTMLK
- X char *dotmlk;
- X#endif
- X
- X#ifdef ML_DOTLOCK
- X if ((dotlock = dotlock_name(name)) == NULL
- X || remove_lockfile(dotlock) < 0)
- X ret = -1;
- X#endif /* ML_DOTLOCK */
- X
- X#ifdef ML_DOTMLK
- X if ((dotmlk = dotmlk_name(name)) == NULL
- X || remove_lockfile(dotmlk) < 0)
- X ret = -1;
- X#endif /* ML_DOTMLK */
- X
- X return ret;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Lock a file descriptor.
- X */
- X
- Xint
- Xlock_fd(fd)
- Xint fd;
- X{
- X#ifdef ML_FCNTL
- X struct flock fl;
- X
- X fl.l_type = F_WRLCK;
- X fl.l_whence = 0;
- X fl.l_start = 0L;
- X fl.l_len = 0L;
- X
- X if (fcntl(fd, F_SETLKW, &fl) == -1)
- X {
- X syserr("can't lock with fcntl()");
- X return -1;
- X }
- X
- X if (verbose)
- X message("locked mailbox with fcntl()\n");
- X#endif /* ML_FCNTL */
- X
- X#ifdef SIMPLE_LOCK
- X long pos;
- X
- X if ((pos = lseek(fd, 0L, 0)) == -1)
- X {
- X syserr("can't seek in mailbox");
- X return -1;
- X }
- X if (LOCKFD(fd, 0L) == -1)
- X {
- X syserr("can't lock with %s()", SIMPLE_LOCK);
- X return -1;
- X }
- X if (lseek(fd, pos, 0) == -1)
- X {
- X syserr("can't seek in mailbox");
- X return -1;
- X }
- X
- X if (verbose)
- X message("locked mailbox with %s()\n", SIMPLE_LOCK);
- X#endif /* SIMPLE_LOCK */
- X
- X /* Default: success */
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Unlock a file descriptor.
- X */
- X
- Xint
- Xunlock_fd(fd)
- Xint fd;
- X{
- X#ifdef ML_FCNTL
- X struct flock fl;
- X
- X fl.l_type = F_UNLCK;
- X fl.l_whence = 0;
- X fl.l_start = 0L;
- X fl.l_len = 0L;
- X
- X if (fcntl(fd, F_SETLKW, &fl) == -1)
- X {
- X syserr("can't unlock with fcntl()");
- X return -1;
- X }
- X
- X if (verbose)
- X message("unlocked mailbox with fcntl()\n");
- X#endif /* ML_FCNTL */
- X
- X#ifdef SIMPLE_LOCK
- X long pos;
- X
- X if ((pos = lseek(fd, 0L, 0)) == -1)
- X {
- X syserr("can't seek in mailbox");
- X return -1;
- X }
- X if (LOCKFD(fd, 0L) == -1)
- X {
- X syserr("can't unlock with %s()", SIMPLE_LOCK);
- X return -1;
- X }
- X if (lseek(fd, pos, 0) == -1)
- X {
- X syserr("can't seek in mailbox");
- X return -1;
- X }
- X
- X if (verbose)
- X message("unlocked mailbox with %s()\n", SIMPLE_LOCK);
- X#endif /* SIMPLE_LOCK */
- X
- X /* Default: success */
- X return 0;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Return the name of the appropriate ".lock" file for a mailbox.
- X */
- X
- X#ifdef ML_DOTLOCK
- X
- Xstatic char *
- Xdotlock_name(name)
- Xchar *name;
- X{
- X static char *lname = NULL;
- X static int lsize = 0;
- X char *p;
- X int n, i;
- X
- X n = strlen(name);
- X if (lsize < n + 8)
- X {
- X if (lname)
- X free(lname);
- X lsize = n + 32;
- X lname = zalloc(lsize);
- X }
- X
- X (void) strcpy(lname, name);
- X
- X /*
- X * We want as much of `basename.lock' as will fit in a string
- X * MAX_NAMESIZE long.
- X */
- X for (i = 0, p = basename(lname); (i < MAX_NAMESIZE - 5) && (*p); ++i)
- X ++p;
- X (void) strcpy(p, ".lock");
- X
- X return lname;
- X}
- X
- X#endif /* ML_DOTLOCK */
- X
- X/*----------------------------------------------------------------------
- X * Return the name of the appropriate ".mlk" file for a mailbox.
- X */
- X
- X#ifdef ML_DOTMLK
- X
- Xstatic char *
- Xdotmlk_name(name)
- Xchar *name;
- X{
- X static char lname[MAX_NAMESIZE + 16];
- X char *p, *d;
- X int i;
- X
- X /*
- X * To explain the below: If we ass_u_me that MAX_NAMESIZE is 14,
- X * then this code is like `printf(lname, "/tmp/%.10s.mlk", ...)'.
- X * In other words, we want as much of `basename.mlk' as will fit
- X * in a string MAX_NAMESIZE long.
- X */
- X d = lname;
- X for (p = "/tmp/"; *p; )
- X *d++ = *p++;
- X for (i = 0, p = basename(name); (i < MAX_NAMESIZE - 4) && (*p); ++i)
- X *d++ = *p++;
- X (void) strcpy(d, ".mlk");
- X
- X return lname;
- X}
- X
- X#endif /* ML_DOTMLK */
- X
- X/*----------------------------------------------------------------------
- X * Create a lockfile.
- X */
- X
- Xint
- Xcreate_lockfile(name)
- Xchar *name;
- X{
- X int tries, fd;
- X
- X for (tries = 0; tries < 10; ++tries)
- X {
- X if (tries)
- X snooze(3);
- X
- X if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0)) >= 0)
- X {
- X (void) close(fd);
- X if (verbose)
- X message("created lockfile %s\n", name);
- X return 0;
- X }
- X
- X if (verbose && (tries == 0))
- X {
- X message("Waiting to create %s (try #%d)\n",
- X name, tries + 1);
- X }
- X }
- X
- X syserr("can't create lockfile %s", name);
- X return -1;
- X}
- X
- X/*----------------------------------------------------------------------
- X * Remove a lockfile.
- X */
- X
- Xint
- Xremove_lockfile(name)
- Xchar *name;
- X{
- X if (unlink(name) == -1)
- X {
- X syserr("can't remove lockfile %s", name);
- X return -1;
- X }
- X
- X if (verbose)
- X message("removed lockfile %s\n", name);
- X
- X return 0;
- X}
- END_OF_FILE
- if test 6559 -ne `wc -c <'lock.c'`; then
- echo shar: \"'lock.c'\" unpacked with wrong size!
- fi
- # end of 'lock.c'
- fi
- echo shar: End of shell archive.
- exit 0
-
-